use ash::vk::{self, Offset2D};

use super::{RenderSystem, render_scene::PerMeshUniformData, render_pass::{mesh_render_pass::{MeshPassDescriptorSetLayoutType, MeshPassPipelineType}, post_render_pass::PostRenderPassCreateInfo}};
use crate::{system::{scene::{SceneSystem, object}, MAX_FRAMES_IN_FLIGHT}, vulkan::{vk_context::{self, buffer, command_buffer}, vk_struct::QueueType, vk_utils::{utils_info, utils_pipeline}, VkContext}, VK_CHECK_UNSAFE, VK_LOGD, VK_LOGI, VK_LOGP};

impl RenderSystem {
    pub fn wait_for_fences(&self) {
        VK_CHECK_UNSAFE!(self.vk_context.vk_device.wait_for_fences(&[self.frame_sync_objects[self.current_frame_index].submit_fence], true, u64::MAX));
    }

    pub fn reset_fence(&self) {
        VK_CHECK_UNSAFE!(self.vk_context.vk_device.reset_fences(&[self.frame_sync_objects[self.current_frame_index].submit_fence]));
    }

    /// 重新创建Swapchain
    fn recreate_swapchain(&mut self) {
        let vk_context = &self.vk_context;
        // 等待Device所有的执行命令停止
        vk_context.device_wait_idle();
        VK_CHECK_UNSAFE!(vk_context.vk_device.queue_wait_idle(vk_context.get_vk_queue(QueueType::T).handler));
        VK_CHECK_UNSAFE!(vk_context.vk_device.queue_wait_idle(vk_context.get_vk_queue(QueueType::C).handler));
        VK_CHECK_UNSAFE!(vk_context.vk_device.queue_wait_idle(vk_context.get_vk_queue(QueueType::GTC).handler));
        // 重新创建
        self.swapchain.recreate(&self.vk_context); // swapchain的释放在这里面
    }

    /// 窗口大小改变时，需要修改各个资源的Size
    pub fn on_window_size_changed(&mut self) {
        // 重新创建Swapchain
        self.recreate_swapchain();
        // 重新创建RenderPass资源以及部分Texture Descriptor Set绑定
        let swapchain_extent = self.swapchain.get_extent();
        self.mesh_render_pass.on_window_size_changed(&self.vk_context, &swapchain_extent);

        let post_render_pass_ci         = PostRenderPassCreateInfo {
            swapchain           : &self.swapchain,
            input_texture       : self.mesh_render_pass.get_output_texture()
        };
        self.post_render_pass.on_window_size_changed(&self.vk_context, post_render_pass_ci);
    }

    pub fn acquired_next_image(&mut self) -> (u32, bool) {
        let semaphore = self.frame_sync_objects[self.current_frame_index].image_available_semaphore;
        let swapchain = &self.swapchain;

        match unsafe{ swapchain.function_set.acquire_next_image(swapchain.handler, u64::MAX, semaphore, vk::Fence::null()) } {
            Ok(result) => (result.0, true),
            Err(error_code) => {
                if error_code == vk::Result::ERROR_OUT_OF_DATE_KHR { 
                    self.on_window_size_changed();
                } else {
                    VK_LOGP!("Failed to acquired next image!");
                }
                (0u32, false)
            }
        }
    }

    pub fn reset_command_buffer(&self) {
        VK_CHECK_UNSAFE!(self.vk_context.vk_device.reset_command_buffer(self.frame_command_buffers[self.current_frame_index], vk::CommandBufferResetFlags::empty()));
    }

    pub fn begin_command_buffer(&self) {
        let current_command_buffer = self.frame_command_buffers[self.current_frame_index];

        let command_buffer_begin_info = vk::CommandBufferBeginInfo {
            s_type                  : vk::StructureType::COMMAND_BUFFER_BEGIN_INFO,
            p_next                  : std::ptr::null(),
            flags                   : vk::CommandBufferUsageFlags::empty(),
            p_inheritance_info      : std::ptr::null()
        };
        
        unsafe {
            self.vk_context.vk_device
                .begin_command_buffer(current_command_buffer, &command_buffer_begin_info)
                .expect("failed to begin command buffer!")    
        };
    }

    /// 正常渲染
    /// 
    pub fn render_standard_pass(&self, scene_system: &SceneSystem, delta_time: f32) {
        let mesh_render_pass = &self.mesh_render_pass;
        let current_command_buffer = self.frame_command_buffers[self.current_frame_index];
        // Clear Value可能和FrameBuffer里面的顺序是对应的
        let clear_values = self.mesh_render_pass.get_attachment_clear_values();
        // 绑定render pass和framebuffer，设置clear value
        let mut render_pass_begin_info = utils_info::get_render_pass_begin_info();
        render_pass_begin_info.render_pass              = mesh_render_pass.render_pass;
        render_pass_begin_info.framebuffer              = mesh_render_pass.framebuffers[0];
        render_pass_begin_info.render_area              = vk::Rect2D { offset: Offset2D { x: 0, y: 0 }, extent: self.swapchain.get_extent() };
        render_pass_begin_info.clear_value_count        = clear_values.len() as u32;
        render_pass_begin_info.p_clear_values           = clear_values.as_ptr();
        // 设置Viewport和Scissor
        let viewports               = [utils_pipeline::get_viewport(&self.swapchain.get_extent())];
        let scissors                = [utils_pipeline::get_scissor (&self.swapchain.get_extent())];
        unsafe {
            self.vk_context.vk_device.cmd_set_viewport(current_command_buffer, 0, &viewports);
            self.vk_context.vk_device.cmd_set_scissor (current_command_buffer, 0, &scissors );
        }
        // 绑定Render Pass和Pipeline，然后直接绘制
        // 这里在Shader中使用了技巧，而不需要VertexBuffer和IndexBuffer，在Shader中利用PointIndex构造单个三角形渲染后处理
        unsafe {
            self.vk_context.vk_device.cmd_begin_render_pass(current_command_buffer, &render_pass_begin_info, vk::SubpassContents::INLINE);
        }
        
        // 渲染第一步，设置PerFrameUniformBuffer
        unsafe {
            if let Some(mapped_handler) = mesh_render_pass.perframe_uniform_buffers[self.current_frame_index].mapped_handler {
                mapped_handler.copy_from_nonoverlapping(&self.generate_per_frame_uniform(), 1);
                self.vk_context.vk_device.cmd_bind_descriptor_sets(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, 
                    mesh_render_pass.pipelines[MeshPassPipelineType::MeshPipeline as usize].layout, 
                    0, 
                    &[mesh_render_pass.perframe_descriptor_sets[self.current_frame_index]], 
                    &[])
            }
        }

        // 第二步走渲染管线
        unsafe {
            self.vk_context.vk_device.cmd_bind_pipeline(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, mesh_render_pass.pipelines[MeshPassPipelineType::MeshPipeline as usize].handler);
            for render_entity in &self.render_scene.render_entities {
                let vertex_buffer   = &render_entity.mesh.vertex_buffer;
                let index_buffer    = &render_entity.mesh.index_buffer;
                let index_count     = render_entity.mesh.index_count;

                self.vk_context.vk_device.cmd_bind_vertex_buffers(current_command_buffer, 0, &[vertex_buffer.handler], &[0]);
                self.vk_context.vk_device.cmd_bind_index_buffer(current_command_buffer, index_buffer.handler, 0, vk::IndexType::UINT32);
                self.vk_context.vk_device.cmd_bind_descriptor_sets(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, mesh_render_pass.pipelines[MeshPassPipelineType::MeshPipeline as usize].layout, 
                    MeshPassDescriptorSetLayoutType::PerMesh as u32, &render_entity.per_mesh_descriptor_sets, &[]);
                self.vk_context.vk_device.cmd_draw_indexed(current_command_buffer, index_count, 1, 0, 0, 0);
            }
        }

        // 第三步走Subpass
        unsafe {
            self.vk_context.vk_device.cmd_next_subpass(current_command_buffer, vk::SubpassContents::INLINE);
            self.vk_context.vk_device.cmd_bind_pipeline(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, mesh_render_pass.pipelines[MeshPassPipelineType::InnerPostPipeline as usize].handler);
            self.vk_context.vk_device.cmd_bind_descriptor_sets(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, mesh_render_pass.pipelines[MeshPassPipelineType::InnerPostPipeline as usize].layout, 
                0, &[mesh_render_pass.subpass_descriptor_sets[self.current_frame_index]], &[]);
            self.vk_context.vk_device.cmd_draw(current_command_buffer, 3, 1, 0, 0);
        }

        unsafe {
            self.vk_context.vk_device.cmd_end_render_pass(current_command_buffer);
        }
    }

    /// 后处理渲染
    /// 利用技巧，不需要VertexBuffer，直接渲染三个点
    pub fn render_post_pass(&self, image_index: u32) {
        let post_render_pass = &self.post_render_pass;
        let current_command_buffer = self.frame_command_buffers[self.current_frame_index];
        // Clear Value可能和FrameBuffer里面的顺序是对应的
        let clear_values = [
            utils_pipeline::get_clear_color([0.5f32, 0.5f32, 0.5f32, 0.0f32]),
            utils_pipeline::get_clear_depth_stencil(1.0, 0)
        ];
        // 绑定render pass和framebuffer，设置clear value
        let mut render_pass_begin_info = utils_info::get_render_pass_begin_info();
        render_pass_begin_info.render_pass              = post_render_pass.render_pass;
        render_pass_begin_info.framebuffer              = post_render_pass.framebuffers[image_index as usize];
        render_pass_begin_info.render_area              = vk::Rect2D { offset: Offset2D { x: 0, y: 0 }, extent: self.swapchain.get_extent() };
        render_pass_begin_info.clear_value_count        = clear_values.len() as u32;
        render_pass_begin_info.p_clear_values           = clear_values.as_ptr();
        // 设置Viewport和Scissor
        let viewports               = [utils_pipeline::get_viewport(&self.swapchain.get_extent())];
        let scissors                = [utils_pipeline::get_scissor (&self.swapchain.get_extent())];
        unsafe {
            self.vk_context.vk_device.cmd_set_viewport(current_command_buffer, 0, &viewports);
            self.vk_context.vk_device.cmd_set_scissor (current_command_buffer, 0, &scissors );
        }
        // 绑定Render Pass和Pipeline，然后直接绘制
        // 这里在Shader中使用了技巧，而不需要VertexBuffer和IndexBuffer，在Shader中利用PointIndex构造单个三角形渲染后处理
        unsafe {
            self.vk_context.vk_device.cmd_begin_render_pass(current_command_buffer, &render_pass_begin_info, vk::SubpassContents::INLINE);
            self.vk_context.vk_device.cmd_bind_pipeline(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, post_render_pass.pipeline.handler);
            self.vk_context.vk_device.cmd_bind_descriptor_sets(current_command_buffer, vk::PipelineBindPoint::GRAPHICS, post_render_pass.pipeline.layout, 0, &[post_render_pass.descriptor_sets[self.current_frame_index]], &[]);
            self.vk_context.vk_device.cmd_draw(current_command_buffer, 3, 1, 0, 0);
            self.vk_context.vk_device.cmd_end_render_pass(current_command_buffer);
        }
    }

    pub fn end_command_buffer(&self) {
        let current_command_buffer = self.frame_command_buffers[self.current_frame_index];
        VK_CHECK_UNSAFE!(self.vk_context.vk_device.end_command_buffer(current_command_buffer));
    }

    /// 通过Queue提交Command
    pub fn queue_submit(&self, queue_type: QueueType) {
        let current_sync_object         = &self.frame_sync_objects[self.current_frame_index];
        let current_command_buffer      = self.frame_command_buffers[self.current_frame_index];
        let queue                       = self.vk_context.get_vk_queue(queue_type).handler;

        // 这次Submit需要等待的信号量
        let wait_semaphores     = [current_sync_object.image_available_semaphore];
        let wait_stages         = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
        // 这次Submit需要释放的信号量
        let signal_semaphores   = [current_sync_object.render_finished_semaphore];
        let command_buffer      = [current_command_buffer];
        
        let mut submit_info = utils_info::get_submit_info();
        submit_info.wait_semaphore_count        = wait_semaphores.len() as u32;
        submit_info.p_wait_semaphores           = wait_semaphores.as_ptr();
        submit_info.p_wait_dst_stage_mask       = wait_stages.as_ptr();
        submit_info.command_buffer_count        = command_buffer.len() as u32;
        submit_info.p_command_buffers           = command_buffer.as_ptr();
        submit_info.signal_semaphore_count      = signal_semaphores.len() as u32;
        submit_info.p_signal_semaphores         = signal_semaphores.as_ptr();
        let submit_infos = [submit_info];

        // Queue提交完毕之后Fence Signaled，也就是Fence是用来同步Host和Queue操作的
        VK_CHECK_UNSAFE!(self.vk_context.vk_device.queue_submit(queue, &submit_infos, current_sync_object.submit_fence));
    }

    /// 提交图像到swapchain
    /// 输出result
    pub fn queue_present(&self, image_index: u32) -> bool {
        let current_sync_object     = &self.frame_sync_objects[self.current_frame_index];
        let queue                   = self.vk_context.get_vk_queue(QueueType::T).handler;

        let signal_semaphores       = [current_sync_object.render_finished_semaphore];
        let swapchains              = [self.swapchain.handler];

        let present_info = vk::PresentInfoKHR {
            s_type                  : vk::StructureType::PRESENT_INFO_KHR,
            p_next                  : std::ptr::null(),
            wait_semaphore_count    : signal_semaphores.len() as u32,
            p_wait_semaphores       : signal_semaphores.as_ptr(),
            swapchain_count         : swapchains.len() as u32,
            p_swapchains            : swapchains.as_ptr(),
            p_image_indices         : &image_index,
            p_results               : std::ptr::null_mut()
        };

        match unsafe {self.swapchain.function_set.queue_present(queue, &present_info) } {
            Ok(result_bool) => result_bool,
            Err(error_code) => {
                if error_code == vk::Result::ERROR_OUT_OF_DATE_KHR {
                    true
                } else {
                    VK_LOGP!("Failed to queue_present");
                }
            }
        }
    }

    /// 每帧最开始前调用的函数
    /// 1. 等待上一次Submit
    /// 2. 向Swapchain申请ImageIndex，如果窗口有更新会触发Recreate
    /// 3. 重置这帧需要的信息，包括了Fence与Command Buffer
    pub fn before_frame(&mut self) -> Option<u32> {
        // 最小化不显示
        if self.vk_context.g_window.is_minimized().unwrap_or(true) {
            return None;
        }
        // 等待上次一Submit结束
        self.wait_for_fences();
        // 向Swapchain申请Image，如果有变动会重新创建Swapchain
        let (image_index, result_code) = self.acquired_next_image();
        if result_code == false {
            return None;
        }
        // 重置这帧需要的信息
        self.reset_fence();
        self.reset_command_buffer();
        self.begin_command_buffer();

        return Some(image_index)
    }

    /// 每帧结束后调用的函数
    /// 1. 结束Command Buffer
    /// 2. 提交这段Command Buffer的渲染结果
    /// 3. current_frame_index增加
    pub fn after_frame(&mut self, image_index: u32) {
        // 结束Command Buffer收集Command
        self.end_command_buffer();
        // 提交当帧渲染结果
        self.queue_submit(QueueType::GTC);
        let result_code = self.queue_present(image_index);
        // 调整为下一帧的Context
        self.vk_context.current_frame_index = (self.vk_context.current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
        if result_code == false {
            return;
        }
    }

    pub fn tick(&mut self, scene_system: &SceneSystem, delta_time: f32) {
        // VK_LOGD!(format!("Render Tick  1 {}", self.current_frame_index));
        let image_index = match self.before_frame() {
            Some(image_index)   => image_index,
            None                => return
        };
        // Pre Frame Setting
        self.vk_context.current_image_index     = image_index as usize;
        self.vk_context.current_command_buffer  = self.frame_command_buffers[self.current_frame_index];
        self.render_scene.update(scene_system);

        self.render_standard_pass(scene_system, delta_time);
        // VK_LOGD!(format!("Render Tick  2 {}", self.current_frame_index));
        self.render_post_pass(image_index);
        // VK_LOGD!(format!("Render Tick  3 {}", self.current_frame_index));
        self.after_frame(image_index);
        // VK_LOGD!(format!("Render Tick  4 {}", self.current_frame_index));
    }
}